#pragma once
#ifndef  __TEMPLATEPRE_H__
#define __TEMPLATEPRE_H__

#include<iostream>
#include<vector>

using namespace std;

template<typename T,
	template<typename C, typename = std::allocator<C>> class Contianer = std::vector>
struct Stack
{
	void push(const T& elem)
	{
		elems.push_back(elem);
	}

	T Pop()
	{
		if (Empty()) throw std::out_of_range("Stack is Empty!");
		T elem = elems.back();
		elems.pop_back();
		return elem;
	}

	bool Empty() const
	{
		return elems.size() == 0;
	}

private:
	Contianer<T> elems;
};


template<int x, int y>
struct Calculate
{
	enum
	{
		Add = x + y,
		Sub = x - y,
		Mul = x*y,
		Div = x / y
	};
};

template<typename T>
struct PointerOf
{
	using Result = T*;
};

#define __pointer(...) typename PointerOf<__VA_ARGS__>::Result

template<int N, typename T, template<typename> class Func>
struct Times
{
	using Result = typename Func<typename Times<N - 1, T, Func>::Result>::Result;
};

template<typename T, template<typename> class Func>
struct Times<1, T, Func>
{
	using Result = typename Func<T>::Result;
};

template<int N>
struct CharPointer :Times<N, char, PointerOf>
{
};

template<int N> using CharPointer1 = Times<N, char, PointerOf>;

template<typename T>
struct Pointer2Of
{
	using Result = __pointer(__pointer(T));
};

template<typename T> using Pointer2Of1 = Times<1, T, PointerOf>;

template<int N>
struct Factorial
{
	enum
	{
		Value = N*Factorial<N - 1>::Value,
	};
};

template<>
struct Factorial<1>
{
	enum
	{
		Value = 1,
	};
};

//template<typename T,typename V>
//struct IsEqual
//{
//	enum
//	{
//		Result = false,
//	};
//};
//
//template<typename T>
//struct IsEqual< T,T>
//{
//	enum
//	{
//		Result = true;
//	};
//};

template<int N, int M>
struct IsNumEqual
{
	enum
	{
		Result = false,
	};
};

template<int N>
struct IsNumEqual<N, N>
{
	enum
	{
		Result = true,
	};
};
#endif // !